import axios from "axios";
import { MessageBox, Message } from "element-ui";
import store from "@/store";
import util from "@/libs/util";
import { dev_api_baseUrl, pro_api_baseUrl } from "@/locales/const.js";
import qs from "qs";

// 记录和显示错误
function errorLog(err) {
  // 添加到日志
  store.dispatch("iClass/log/add", {
    type: "error",
    err,
    info: "数据请求异常"
  });
}

const loginUrl = "blade-auth/oauth/token";

let isRefreshing = false; // 是否正在刷新token

let callbacks = []; // 失效后同时发送请求的容器 -- 缓存接口

// 刷新 token 后, 将缓存的接口重新请求一次
function onAccessTokenFetched(newToken) {
  callbacks.forEach(callback => {
    callback(newToken);
  });
  // 清空缓存接口
  callbacks = [];
}

//  包装参数对象方法
function handleParams(data) {
  return qs.stringify(data);
}

const TIME_OUT_MS = 60 * 1000; // 默认请求超时时间
// 添加缓存接口
function addCallbacks(callback) {
  callbacks.push(callback);
}

// 刷新token
function refreshToken() {
  return service
    .post(
      "/blade-auth/oauth/token",
      handleParams({
        grant_type: "refresh_token",
        refresh_token: util.cookies.get("refresh_token")
      })
    )
    .then(res => {
      return Promise.resolve(res);
    });
}

// 请求ip
let apiUrl = "";
if (process.env.NODE_ENV == "development") {
  apiUrl = dev_api_baseUrl;
} else {
  apiUrl = pro_api_baseUrl;
}

// create an axios instance
const service = axios.create({
  baseURL: apiUrl, // url = base url + request url
  //  withCredentials: true, // send cookies when cross-domain requests
  timeout: 5000 // request timeout
});

// request interceptor
service.interceptors.request.use(
  config => {
    // do something before request is sent
    config.headers["Authorization"] = "Basic c3dvcmQ6c3dvcmRfc2VjcmV0";
    config.headers["Tenant-Id"] = "000000";
    // 在请求发送之前做一些处理
    const token = util.cookies.get("token") || "";
    if (token) {
      config.headers["Blade-Auth"] = token;
    }
    return config;
  },
  error => {
    // do something with request error
    console.log(error); // for debug
    return Promise.reject(error);
  }
);

// response interceptor
service.interceptors.response.use(
  response => {
    //  console.log(response)
    const code = response.status;
    if (code === 200) {
      return response;
    } else {
      return Promise.reject(new Error(res.message || "Error"));
    }
  },
  error => {
    console.log(error.response);
    const code = error.response.status || "";
    const config = error.config;
    // console.log(config)
    if (code === 401 && !config.url.includes(loginUrl)) {
      // 如果当前状态码为401并且请求的不是登陆接口
      /**
       * 将未授权接口缓存起来。retryOriginalRequest 这个 Promise 函数很关键，它一直处于等待状态。
       * 只有当token刷新成功后，onAccessTokenFetched 这个函数执行了回调函数，返回了 resolve 状态
       */
      const retryOriginalRequest = new Promise(resolve => {
        addCallbacks(newToken => {
          // console.log(newToken)
          // console.log(config)
          // 表示用新的token去替换掉原来的token
          config.headers["Blade-Auth"] = newToken;
          // 替换掉url -- 因为baseURL会扩展请求url
          // config.url = config.url.replace(apiUrl, '')
          resolve(service(config)); // 调用resolve请求队列里面接口
        });

        // 无感刷新Token
        if (!isRefreshing) {
          isRefreshing = true;
          refreshToken()
            .then(res => {
              // console.log(res)
              // 用rftoken获取新的token
              const newToken = res.data.access_token;
              const newRefreshToken = res.data.refresh_token;
              util.cookies.set("token", newToken);
              util.cookies.set("refresh_token", newRefreshToken);
              // setToken()
              // setRefreshToken()
              onAccessTokenFetched(newToken);
            })
            .catch(res => {
              // console.log(res)
              // 刷新token报错的话, 就需要跳转到登录页面
              // setToken('')
              // setRefreshToken('')
              Message({
                message: "您长时间未操作系统,请重新登录" || "Error",
                type: "error",
                duration: 2 * 1000
              });
              errorLog(res);
              // 删除cookie
              util.cookies.remove("refresh_token");
              util.cookies.remove("token");
              util.cookies.remove("uuid");
              util.cookies.remove("user-role");
              util.cookies.remove("user-info");
              util.cookies.remove("current-term");
              // 跳转到登录页
              window.location.href = `index.html#/index`;
            })
            .finally(() => {
              isRefreshing = false;
            });
        }
      });
      // 将token过期期间请求的接口包装成promise返回，等待刷新token后重新请求
      return retryOriginalRequest;
    } else if (code === 500) {
      Message({
        message: "服务器内部错误" || "Error",
        type: "error",
        duration: 2 * 1000
      });
      errorLog(error);
    } else if (code === 404) {
      Message({
        message: "资源未找到" || "Error",
        type: "error",
        duration: 2 * 1000
      });
      errorLog(error);
    } else if (code === 403) {
      Message({
        message: "拒绝访问" || "Error",
        type: "error",
        duration: 2 * 1000
      });
      errorLog(error);
    } else if (code === 408) {
      Message({
        message: "请求超时" || "Error",
        type: "error",
        duration: 2 * 1000
      });
      errorLog(error);
    } else if (code === 400) {
      if (error.response.data.error_description === "Bad credentials") {
        Message({
          message: "账号或密码错误",
          type: "error",
          duration: 2 * 1000
        });
      } else {
        Message({
          message: error.response.data.msg,
          type: "error",
          duration: 2 * 1000
        });
      }
      errorLog(error);
    } else {
      return Promise.reject(error);
    }
  }
);

export { apiUrl };
export default service;
